
package com.jf.cloud.multishop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.jf.cloud.api.auth.bo.UserInfoInTokenBO;
import com.jf.cloud.api.auth.constant.SysTypeEnum;
import com.jf.cloud.api.auth.dto.AuthAccountDTO;
import com.jf.cloud.api.auth.feign.AccountFeignClient;
import com.jf.cloud.api.biz.feign.AttachFileFeignClient;
import com.jf.cloud.api.biz.feign.NotifyFeignClient;
import com.jf.cloud.api.coupon.feign.CouponFeignClient;
import com.jf.cloud.api.delivery.feign.SameCityFeignClient;
import com.jf.cloud.api.discount.feign.DiscountFeignClient;
import com.jf.cloud.api.feign.SearchSpuFeignClient;
import com.jf.cloud.api.multishop.bo.EsShopDetailBO;
import com.jf.cloud.api.multishop.bo.ShopSimpleBO;
import com.jf.cloud.api.multishop.constant.ShopStatus;
import com.jf.cloud.api.multishop.vo.ShopDetailVO;
import com.jf.cloud.api.platform.constant.OfflineHandleEventStatus;
import com.jf.cloud.api.platform.constant.OfflineHandleEventType;
import com.jf.cloud.api.platform.dto.OfflineHandleEventDTO;
import com.jf.cloud.api.platform.feign.OfflineHandleEventFeignClient;
import com.jf.cloud.api.platform.vo.OfflineHandleEventVO;
import com.jf.cloud.api.product.feign.*;
import com.jf.cloud.api.seckill.feign.SeckillFeignClient;
import com.jf.cloud.common.cache.constant.CacheNames;
import com.jf.cloud.common.constant.*;
import com.jf.cloud.common.database.dto.PageDTO;
import com.jf.cloud.common.database.util.PageUtil;
import com.jf.cloud.common.database.vo.PageVO;
import com.jf.cloud.common.exception.LuckException;
import com.jf.cloud.common.i18n.I18nMessage;
import com.jf.cloud.common.order.constant.ShopType;
import com.jf.cloud.common.product.constant.SalesPriceType;
import com.jf.cloud.common.product.constant.SalesType;
import com.jf.cloud.common.product.dto.ProductSearchLimitDTO;
import com.jf.cloud.common.product.vo.search.SpuSearchVO;
import com.jf.cloud.common.response.ResponseEnum;
import com.jf.cloud.common.response.ServerResponseEntity;
import com.jf.cloud.common.security.AuthUserContext;
import com.jf.cloud.common.util.IpHelper;
import com.jf.cloud.multishop.constant.AuditStatus;
import com.jf.cloud.multishop.constant.ShopWalletZoneConstant;
import com.jf.cloud.multishop.dto.*;
import com.jf.cloud.multishop.mapper.ShopDetailMapper;
import com.jf.cloud.multishop.mapper.ShopUserMapper;
import com.jf.cloud.multishop.mapper.ShopWalletMapper;
import com.jf.cloud.multishop.model.*;
import com.jf.cloud.multishop.service.*;
import com.jf.cloud.multishop.vo.ShopAuditingVO;
import com.jf.cloud.multishop.vo.ShopCompanyVO;
import com.jf.cloud.multishop.vo.ShopDetailAppVO;
import com.jf.cloud.multishop.vo.ShopHeadInfoVO;
import io.seata.spring.annotation.GlobalTransactional;
import ma.glasnost.orika.MapperFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 店铺详情
 *
 * @author zz
 * @date 2020-11-23 16:24:29
 */
@Service
public class ShopDetailServiceImpl implements ShopDetailService {
    private static final Logger log = LoggerFactory.getLogger(ShopDetailServiceImpl.class);

    @Autowired
    private ShopDetailMapper shopDetailMapper;
    @Autowired
    private ShopCompanyService shopCompanyService;
    @Autowired
    private ShopAuditingService shopAuditingService;
    @Autowired
    private SearchSpuFeignClient searchSpuFeignClient;
    @Autowired
    private ShopWalletMapper shopWalletMapper;
    @Autowired
    private ShopUserService shopUserService;
    @Autowired
    private MapperFacade mapperFacade;
    @Autowired
    private ShopExtensionService shopExtensionService;
    @Autowired
    private AccountFeignClient accountFeignClient;
    @Autowired
    private SpuFeignClient spuFeignClient;
    @Autowired
    private ShopUserMapper shopUserMapper;
    @Autowired
    private BrandFeignClient brandFeignClient;
    @Autowired
    private OfflineHandleEventFeignClient offlineHandleEventFeignClient;
    @Autowired
    private NotifyFeignClient notifyFeignClient;
    @Autowired
    private ShopBankCardService shopBankCardService;
    @Autowired
    private CategoryShopFeignClient categoryShopFeignClient;
    @Autowired
    private BrandShopFeignClient brandShopFeignClient;
    @Autowired
    private SameCityFeignClient sameCityFeignClient;
    @Autowired
    private ShopCartFeignClient shopCartFeignClient;
    @Autowired
    private AttachFileFeignClient attachFileFeignClient;
    @Autowired
    private SeckillFeignClient seckillFeignClient;
    @Autowired
    private IndexImgService indexImgService;
    @Autowired
    private DiscountFeignClient discountFeignClient;
    @Autowired
    private CouponFeignClient couponFeignClient;
    @Autowired
    private ShopSubstituteSalesService shopSubstituteSalesService;

    @Override
    public PageVO<ShopDetailVO> page(PageDTO pageDTO, ShopDetailDTO shopDetailDTO) {
        return PageUtil.doPage(pageDTO, () -> shopDetailMapper.list(shopDetailDTO));
    }

    @Override
    @Cacheable(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#shopId")
    public ShopDetailVO getByShopId(Long shopId) {
        return shopDetailMapper.getByShopId(shopId);
    }

    @Override
    public void save(ShopDetail shopDetail) {
        shopDetailMapper.save(shopDetail);
    }

    @Override
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#shopDetailDTO.shopId")
    @Transactional(rollbackFor = Exception.class)
    public void update(ShopDetailDTO shopDetailDTO) {
        this.checkShopInfo(shopDetailDTO, false);
        ShopDetail shopDetail = mapperFacade.map(shopDetailDTO, ShopDetail.class);
        // 若经纬度数据变更，需清空同城配送中的位置信息
        ShopDetailVO dbShopDetail = shopDetailMapper.getByShopId(shopDetail.getShopId());
        if ((dbShopDetail.getShopLng() != null && dbShopDetail.getShopLat() != null)
                && (!dbShopDetail.getShopLat().equals(shopDetail.getShopLat()) || !dbShopDetail.getShopLng().equals(shopDetail.getShopLng()))) {
            sameCityFeignClient.clearPositionInfo(shopDetail.getShopId());
        }
        // 更新商品
        spuFeignClient.updateSpuByShopId(shopDetail.getShopId(), SysTypeEnum.MULTISHOP.value());
        shopDetailMapper.update(shopDetail);
    }

    @Override
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#shopId")
    public void deleteById(Long shopId) {
        shopDetailMapper.deleteById(shopId);
    }

    @Override
    public List<ShopDetail> listByShopIds(List<Long> shopIds) {
        if (CollUtil.isEmpty(shopIds)) {
            return new ArrayList<>();
        }
        return shopDetailMapper.listByShopIds(shopIds);
    }

    @Override
    public PageVO<ShopDetailAppVO> shopSearchPage(PageDTO pageDTO, ShopDetailDTO shopDetailDTO) {
        PageVO<ShopDetailAppVO> page = PageUtil.doPage(pageDTO, () -> shopDetailMapper.shopSearchList(shopDetailDTO));
        Set<Long> spuIdSet = page.getList().stream().map(ShopDetailAppVO::getShopId).collect(Collectors.toSet());
        if (Objects.isNull(shopDetailDTO.getSpuNum()) || shopDetailDTO.getSpuNum() <= 0) {
            return page;
        }
        ProductSearchLimitDTO productSearchLimitDTO = new ProductSearchLimitDTO(shopDetailDTO.getSpuNum());
        productSearchLimitDTO.setShopIds(new ArrayList<>(spuIdSet));
        ServerResponseEntity<List<SpuSearchVO>> spuResponse = searchSpuFeignClient.limitSpuList(productSearchLimitDTO);
        if (!Objects.equals(spuResponse.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(spuResponse.getMsg());
        } else if (CollectionUtil.isEmpty(spuResponse.getData())) {
            return page;
        }
        List<SpuSearchVO> data = spuResponse.getData();
        Map<Long, List<SpuSearchVO>> shopMap = data.stream().collect(Collectors.groupingBy(SpuSearchVO::getShopId));
        for (ShopDetailAppVO shopDetail : page.getList()) {
            List<SpuSearchVO> spuSearchVOList = shopMap.get(shopDetail.getShopId());
            if (CollUtil.isEmpty(spuSearchVOList)) {
                spuSearchVOList = new ArrayList<>();
            }
            shopDetail.setSpuList(spuSearchVOList);
        }
        return page;
    }

    @Override
    public List<ShopDetailAppVO> shopSearchNear(ShopDetailDTO shopDetailDTO) {
        //获取当前店铺一级分类集合
//        List<Long> cateIds=categoryShopFeignClient.getOneCategoryIdByShopId(shopDetailDTO.getShopId(),SysTypeEnum.MULTISHOP.value(), I18nMessage.getLang()).getData();
        //获取附近5公里的100家店铺
        List<Map<String,Object>> useShopIds=shopDetailMapper.getShopIdByNear(Double.valueOf(shopDetailDTO.getShopLng()),Double.valueOf(shopDetailDTO.getShopLat()));
//        if(Objects.isNull(shopIds) || shopIds.size()==0){//附近5公里没有店铺
//            return  new ArrayList<>();
//        }
        //根据一级分类查找5公里内的同类店铺
//        List<Long> useShopIds=categoryShopFeignClient.getShopIdByCategoryIds(cateIds.toArray(),shopIds.toArray()).getData();
        if(useShopIds.size()==0 || Objects.isNull(useShopIds)){
            return new ArrayList<>();
        }
        //根据店铺ID集合筛选符合当前店铺一级分类的
        List<ShopDetailAppVO> list=new ArrayList<>();
        for (int i = 0; i < useShopIds.size(); i++) {
            ShopDetailAppVO shopDetailAppVo=shopDetailMapper.getShopListById(Long.valueOf(useShopIds.get(i).get("shop_id").toString()));
            if(Objects.isNull(shopDetailAppVo)){
                continue;
            }
            shopDetailAppVo.setDis(useShopIds.get(i).get("dis").toString());
            list.add(shopDetailAppVo);
        }
        if(Objects.isNull(list) || list.size()==0){
            return null;
        }
        Set<Long> spuIdSet =list.stream().map(ShopDetailAppVO::getShopId).collect(Collectors.toSet());
        if (Objects.isNull(shopDetailDTO.getSpuNum()) || shopDetailDTO.getSpuNum() <= 0) {
            return list;
        }
        ProductSearchLimitDTO productSearchLimitDTO = new ProductSearchLimitDTO(shopDetailDTO.getSpuNum());
        productSearchLimitDTO.setShopIds(new ArrayList<>(spuIdSet));
        ServerResponseEntity<List<SpuSearchVO>> spuResponse = searchSpuFeignClient.limitSpuList(productSearchLimitDTO);
        if (!Objects.equals(spuResponse.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(spuResponse.getMsg());
        } else if (CollectionUtil.isEmpty(spuResponse.getData())) {
            return list;
        }
        List<SpuSearchVO> data = spuResponse.getData();
        Map<Long, List<SpuSearchVO>> shopMap = data.stream().collect(Collectors.groupingBy(SpuSearchVO::getShopId));
        for (ShopDetailAppVO shopDetail : list) {
            List<SpuSearchVO> spuSearchVOList = shopMap.get(shopDetail.getShopId());
            if (CollUtil.isEmpty(spuSearchVOList)) {
                spuSearchVOList = new ArrayList<>();
            }
            shopDetail.setSpuList(spuSearchVOList);
        }
        return list;
    }

    @Override
    public ShopDetailVO getShopByShopId(Long shopId) {
        return shopDetailMapper.getShopByShopId(shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional
    public void applyShop(ShopDetailDTO shopDetailDTO) {
        checkShopInfo(shopDetailDTO, true);
        ShopDetail newShopDetail = mapperFacade.map(shopDetailDTO, ShopDetail.class);
        // 申请开店
        newShopDetail.setShopStatus(ShopStatus.APPLYING.value());
        newShopDetail.setType(ShopType.STOP.value());
        shopDetailMapper.save(newShopDetail);
        shopDetailDTO.setShopId(newShopDetail.getShopId());

        // 插入一条审核记录
        ShopAuditing auditing = new ShopAuditing();
        auditing.setShopId(newShopDetail.getShopId());
        auditing.setCreateTime(new Date());
        auditing.setStatus(AuditStatus.WAITAUDIT.value());
        auditing.setUpdateTime(new Date());
        auditing.setRemarks(shopDetailDTO.getRemarks());
        shopAuditingService.save(auditing);
        // 创建账号
        createShopAccount(shopDetailDTO, StatusEnum.DELETE);
    }

    /**
     * 审核商家信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void audit(ShopAuditingDTO shopAuditingDTO) {
        Date now = new Date();
        ShopAuditingVO dbShopAyditing = shopAuditingService.getByshopId(shopAuditingDTO.getShopId());
        Long shopUserId = shopUserMapper.getUserIdByShopId(shopAuditingDTO.getShopId());
        if (Objects.isNull(dbShopAyditing)) {
            throw new LuckException(ResponseEnum.DATA_ERROR);
        }
        shopAuditingDTO.setShopAuditingId(dbShopAyditing.getShopAuditingId());
        // 非待审核的店铺，不能再进行审核
        if (!Objects.equals(dbShopAyditing.getStatus(), AuditStatus.WAITAUDIT.value())) {
            throw new LuckException(ResponseEnum.DATA_ERROR);
        }
        // 修改店铺状态
        ShopDetailVO shopDetailVO = getByShopId(shopAuditingDTO.getShopId());
        if (shopDetailVO == null) {
            // 店铺信息不存在
            throw new LuckException("店铺信息不存在");
        }
        Long userId = shopUserService.getUserIdByShopId(shopDetailVO.getShopId());

        ShopDetail shopDetail = mapperFacade.map(shopDetailVO, ShopDetail.class);
        UserInfoInTokenBO userInfoInTokenBO = new UserInfoInTokenBO();
        userInfoInTokenBO.setUserId(userId);
        userInfoInTokenBO.setSysType(SysTypeEnum.MULTISHOP.value());
        userInfoInTokenBO.setTenantId(shopAuditingDTO.getShopId());
        userInfoInTokenBO.setIsAdmin(UserAdminType.ADMIN.value());
        // 审核不通过
        if (Objects.equals(shopAuditingDTO.getStatus(), AuditStatus.FAILAUDIT.value())) {
            shopDetail.setShopStatus(ShopStatus.APPLYING.value());
        }
        // 审核通过
        else {
            shopDetail.setType(shopAuditingDTO.getShopType());
            shopDetail.setContractStartTime(DateUtil.beginOfDay(shopAuditingDTO.getContractStartTime()));
            shopDetail.setContractEndTime(getSaveEndOfDay(shopAuditingDTO.getContractEndTime()));
            if (now.compareTo(shopDetail.getContractStartTime()) >= 0 && now.compareTo(shopDetail.getContractEndTime()) < 0) {
                // 如果店铺的签约时间包含当前时间，则把店铺状态置为营业中
                shopDetail.setShopStatus(ShopStatus.OPEN.value());
            } else {
                // 如果店铺的签约时间不包含当前时间，则把店铺状态置为停业中
                shopDetail.setShopStatus(ShopStatus.STOP.value());
            }
            shopDetail.setIsPreferred(IsPassShopEnum.NO.value());
            updateShopCompanyStatus(shopDetail.getShopId(), AuditStatus.SUCCESSAUDIT.value());
            userInfoInTokenBO.setIsPassShop(IsPassShopEnum.YES.value());
            ServerResponseEntity<Void> updateTenantIdRes = accountFeignClient.updateUserInfoByUserIdAndSysType(userInfoInTokenBO, shopUserId, SysTypeEnum.MULTISHOP.value());
            if (!updateTenantIdRes.isSuccess()) {
                throw new LuckException("审核失败");
            }
            // 把商家自定义品牌添加为平台品牌
            brandFeignClient.updateCustomBrandToPlatformBrandByShopId(shopAuditingDTO.getShopId(), SysTypeEnum.MULTISHOP.value());
            // 新店初始化事件 (分销设置（暂无）), 分销设置是平台统一设置，店铺暂无分销设置
        }
        shopAuditingDTO.setAuditorId(AuthUserContext.get().getUserId());
        shopAuditingService.update(mapperFacade.map(shopAuditingDTO, ShopAuditing.class));
        shopDetailMapper.update(shopDetail);
    }

    /**
     *  更新店铺工商信息审核状态
     * @param shopId
     * @param status
     */
    private void updateShopCompanyStatus(Long shopId, Integer status) {
        ShopCompanyVO shopCompanyWaitAudit = shopCompanyService.getShopCompanyByShopIdAndStatus(shopId, AuditStatus.WAITAUDIT.value());
        if (Objects.isNull(shopCompanyWaitAudit)){
            throw new LuckException("缺少店铺工商资料");
        }
        ShopCompany shopCompany = mapperFacade.map(shopCompanyWaitAudit, ShopCompany.class);
        shopCompany.setStatus(status);
        shopCompanyService.updateByShopId(shopCompany, shopId, 0);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional
    public void changeSpuStatus(Long shopId, Integer shopStatus) {
        shopDetailMapper.changeShopStatus(shopId, shopStatus);
        // 店铺
        if (!StatusEnum.offlineOrDelete(shopStatus)) {
            return;
        }
        // 将该店铺所有的商品下线
        ServerResponseEntity<Void> spuResponse = spuFeignClient.offlineSpuByShopId(shopId);
        if (!Objects.equals(spuResponse.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(spuResponse.getMsg());
        }
    }

    @Override
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#shopId")
    public void removeCacheByShopId(Long shopId) {

    }

    @Override
    public EsShopDetailBO shopExtensionData(Long shopId) {
        return shopDetailMapper.shopExtensionData(shopId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void createShop(ShopDetailDTO shopDetailDTO) {
        checkShopInfo(shopDetailDTO, true);
        ShopDetail shopDetail = mapperFacade.map(shopDetailDTO, ShopDetail.class);
        // 赋默认值
        shopDetail.setType(ShopType.STOP.value());
        shopDetail.setShopStatus(ShopStatus.APPLYING.value());
        shopDetailMapper.save(shopDetail);

        // 创建店铺数据
        addShopInfo(shopDetail.getShopId());

        Long shopUserId = AuthUserContext.get().getUserId();
        // 更新文件记录表中shopId
        ServerResponseEntity<Void> attachRes = attachFileFeignClient.updateShopIdByUid(shopDetail.getShopId());
        if (attachRes.isFail()) {
            throw new LuckException(attachRes.getMsg());
        }
        // 保存shopId到店铺用户表
        if (shopUserMapper.updateShopIdByShopUserId(shopDetail.getShopId(), shopUserId) != 1) {
            throw new LuckException("保存店铺信息错误");
        }
        // 保存shopId到账号表
        UserInfoInTokenBO userInfoInTokenBO = AuthUserContext.get();
        userInfoInTokenBO.setTenantId(shopDetail.getShopId());
        ServerResponseEntity<Void> updateTenantIdRes = accountFeignClient.updateUserInfoByUserIdAndSysType(userInfoInTokenBO, shopUserId, SysTypeEnum.MULTISHOP.value());
        if (!updateTenantIdRes.isSuccess()) {
            throw new LuckException(updateTenantIdRes.getMsg());
        }

        // 保存店铺代销设置默认值
        ShopSubstituteSales shopSubstituteSales = new ShopSubstituteSales();
        shopSubstituteSales.setShopId(shopDetail.getShopId());
        shopSubstituteSales.setSalesType(SalesType.MANUAL_OPERATION_PRICE.value());
        shopSubstituteSales.setOrderShape(0);
        shopSubstituteSales.setSalesPriceType(SalesPriceType.PROPORTION_PRICE.value());
        shopSubstituteSales.setSalesPrice(0L);
        shopSubstituteSalesService.save(shopSubstituteSales);
    }

    @Override
    public List<ShopDetailVO> getShopDetailByShopIdsShopName(List<Long> shopIds,String shopName) {
        return shopDetailMapper.getShopDetailByShopIdsShopName(null,shopName);
    }

    @Override
    public ShopDetailVO getShoExtensionsByShopId(Long shopId) {
        return shopDetailMapper.getShoExtensionsByShopId(shopId);
    }

    @Override
    public Integer countByMobile(String mobile) {
        return shopDetailMapper.countByMobile(mobile);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#shopDetailVO.shopId")
    @GlobalTransactional(rollbackFor = Exception.class)
    public void offline(ShopDetailVO shopDetailVO, String offlineReason, Long sysUserId) {
        Integer sysType = SysTypeEnum.MULTISHOP.value();
        // 添加下线处理记录
        Date now = new Date();
        OfflineHandleEventDTO offlineHandleEventDTO = new OfflineHandleEventDTO();
        offlineHandleEventDTO.setHandleId(shopDetailVO.getShopId());
        offlineHandleEventDTO.setHandleType(OfflineHandleEventType.SHOP.getValue());
        offlineHandleEventDTO.setOfflineReason(offlineReason);
        offlineHandleEventDTO.setHandlerId(sysUserId);
        offlineHandleEventDTO.setSysType(sysType);
        offlineHandleEventDTO.setStatus(OfflineHandleEventStatus.OFFLINE_BY_PLATFORM.getValue());
        offlineHandleEventDTO.setShopId(shopDetailVO.getShopId());
        ServerResponseEntity<OfflineHandleEventVO> processingEventByHandleTypeAndHandleId = offlineHandleEventFeignClient.getProcessingEventByHandleTypeAndHandleId(OfflineHandleEventType.SHOP.getValue(), shopDetailVO.getShopId(), sysType);
        if (processingEventByHandleTypeAndHandleId.isSuccess() && Objects.nonNull(processingEventByHandleTypeAndHandleId.getData())) {
            offlineHandleEventFeignClient.update(offlineHandleEventDTO);
        } else {
            offlineHandleEventFeignClient.save(offlineHandleEventDTO);
        }
        // 更新店铺状态为下线
        shopDetailMapper.changeShopStatus(shopDetailVO.getShopId(), ShopStatus.OFFLINE.value());

        // 将店铺所有商品下线
        ServerResponseEntity<Void> spuResponseEntity = spuFeignClient.offlineSpuByShopId(shopDetailVO.getShopId());
        if (spuResponseEntity.isFail()) {
            throw new LuckException(spuResponseEntity.getMsg());
        }

        // 失效秒杀活动
        ServerResponseEntity<Void> seckillResponseEntity = seckillFeignClient.offlineSeckillByShopId(shopDetailVO.getShopId());
        if (seckillResponseEntity.isFail()) {
            throw new LuckException(seckillResponseEntity.getMsg());
        }

        // 下线满减优惠券活动
        offlineShopActivity(Collections.singletonList(shopDetailVO.getShopId()), ShopStatus.STOP.value());

        //解绑平台轮播图商品
        offlineIndexImg(shopDetailVO.getShopId());
    }

    private void offlineIndexImg(Long shopId) {
        ServerResponseEntity<List<Long>> spuIdsEntity = spuFeignClient.listSpuIdsByShopId(shopId);
        if (spuIdsEntity.isFail()) {
            throw new LuckException(spuIdsEntity.getMsg());
        }
        List<Long> spuIds = spuIdsEntity.getData();
        if (CollUtil.isNotEmpty(spuIds)) {
            indexImgService.offlineSpuBySpuIds(Constant.PLATFORM_SHOP_ID, spuIds);
        }
    }

    @Override
    public Long countByShopStatus(Integer shopStatus) {
        return shopDetailMapper.countByShopStatus(shopStatus);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void platformCreateShop(ShopCreateInfoDTO shopCreateInfoDTO) {
        // 1、校验验证码信息
        ShopUserRegisterDTO shopUserRegisterInfo = shopCreateInfoDTO.getShopUserRegisterInfo();
        ServerResponseEntity<Boolean> sendNotifyResponse = notifyFeignClient.checkValidCode(shopUserRegisterInfo.getMobile(), shopUserRegisterInfo.getValidCode(), SendTypeEnum.VALID);
        Boolean data = sendNotifyResponse.getData();
        if (Objects.equals(sendNotifyResponse.getCode(), ResponseEnum.OK.value()) && Objects.nonNull(data) && !data) {
            throw new LuckException("验证码有误或已过期");
        }
        // 2、保存店铺基本信息
        Date now = new Date();
        ShopDetailDTO shopDetailDTO = shopCreateInfoDTO.getShopDetail();
        this.checkShopInfo(shopDetailDTO, true);
        ShopDetail shopDetail = mapperFacade.map(shopDetailDTO, ShopDetail.class);
        if (Objects.isNull(shopDetail.getContractStartTime()) || Objects.isNull(shopDetail.getContractEndTime())) {
            throw new LuckException("店铺签约时间不能为空");
        }
        shopDetail.setContractStartTime(DateUtil.beginOfDay(shopDetail.getContractStartTime()));
        shopDetail.setContractEndTime(getSaveEndOfDay(shopDetail.getContractEndTime()));
        shopDetail.setIsPreferred(IsPassShopEnum.NO.value());
        if (now.compareTo(shopDetail.getContractStartTime()) >= 0 && now.compareTo(shopDetail.getContractEndTime()) < 0) {
            // 如果店铺的签约时间包含当前时间，则把店铺状态置为营业中
            shopDetail.setShopStatus(ShopStatus.OPEN.value());
        } else {
            // 如果店铺的签约时间不包含当前时间，则把店铺状态置为停业中
            shopDetail.setShopStatus(ShopStatus.STOP.value());
        }
        shopDetailMapper.save(shopDetail);
        Long shopId = shopDetail.getShopId();
        // 3、保存店铺账号信息
        ShopUser shopUser = new ShopUser();
        shopUser.setNickName(shopUserRegisterInfo.getUsername());
        shopUser.setPhoneNum(shopUserRegisterInfo.getMobile());
        shopUser.setHasAccount(1);
        shopUser.setShopId(shopId);
        shopUserService.save(shopUser, null);

        AuthAccountDTO authAccountDTO = new AuthAccountDTO();
        authAccountDTO.setPhone(shopUserRegisterInfo.getMobile());
        authAccountDTO.setPassword(shopUserRegisterInfo.getPassword());
        authAccountDTO.setStatus(StatusEnum.ENABLE.value());
        authAccountDTO.setCreateIp(IpHelper.getIpAddr());
        authAccountDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        authAccountDTO.setIsAdmin(UserAdminType.ADMIN.value());
        authAccountDTO.setTenantId(shopId);
        authAccountDTO.setIsPassShop(IsPassShopEnum.YES.value());
        authAccountDTO.setUsername(shopUserRegisterInfo.getUsername());
        authAccountDTO.setUserId(shopUser.getShopUserId());
        ServerResponseEntity<Long> save = accountFeignClient.save(authAccountDTO);
        if (!Objects.equals(save.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(save.getMsg());
        }
        // 4、初始化店铺数据
        addShopInfo(shopId);
        // 5、初始化店铺审核信息，平台端创建店铺默认为审核成功
        ShopAuditing shopAuditing = new ShopAuditing();
        shopAuditing.setShopId(shopId);
        shopAuditing.setUserId(shopUser.getShopUserId());
        shopAuditing.setAuditorId(AuthUserContext.get().getUserId());
        shopAuditing.setStatus(AuditStatus.SUCCESSAUDIT.value());
        shopAuditingService.save(shopAuditing);
        // 6、保存店铺工商信息
        ShopCompanyDTO shopCompanyDTO = shopCreateInfoDTO.getShopCompany();
        shopCompanyDTO.setShopId(shopDetail.getShopId());
        ShopCompany shopCompany = mapperFacade.map(shopCompanyDTO, ShopCompany.class);
        shopCompany.setStatus(AuditStatus.SUCCESSAUDIT.value());
        shopCompanyService.save(shopCompany, true);
        // 7、保存店铺银行卡信息
        shopBankCardService.insertBatch(shopCreateInfoDTO.getShopBankCardList(), shopId);
        // 8、保存分类签约信息
        ServerResponseEntity<Void> categoryRes = categoryShopFeignClient.insertBatchByShopId(shopCreateInfoDTO.getCategorySigningList(), shopId, SysTypeEnum.MULTISHOP.value());
        if (!categoryRes.isSuccess()) {
            throw new LuckException(categoryRes.getMsg());
        }
        // 9、保存品牌签约信息
        ServerResponseEntity<Void> brandRes = brandShopFeignClient.insertBatchByShopId(shopCreateInfoDTO.getBrandSigningList(), shopId, SysTypeEnum.MULTISHOP.value());
        if (!brandRes.isSuccess()) {
            throw new LuckException(brandRes.getMsg());
        }

        // 保存店铺代销设置默认值
        ShopSubstituteSales shopSubstituteSales = new ShopSubstituteSales();
        shopSubstituteSales.setShopId(shopDetail.getShopId());
        shopSubstituteSales.setSalesType(SalesType.MANUAL_OPERATION_PRICE.value());
        shopSubstituteSales.setOrderShape(0);
        shopSubstituteSalesService.save(shopSubstituteSales);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    public void changeShopStatusByContractTime(Date now) {
        // 获取状态需要改变为停业状态的店铺id列表
        List<Long> shopIdsToStop = shopDetailMapper.listShopIdsOfStatusChangeToStopByContractTime(now);
        // 获取状态需要改变为营业状态的店铺id列表
        List<Long> shopIdsToOpen = shopDetailMapper.listShopIdsOfStatusChangeToOpenByContractTime(now);
        if (CollUtil.isEmpty(shopIdsToStop) && CollUtil.isEmpty(shopIdsToOpen)) {
            // 没有店铺状态需要改变
            return;
        }
        // 根据签约时间修改店铺状态
        shopDetailMapper.changeShopStatusByContractTime(now);
        if (CollUtil.isNotEmpty(shopIdsToStop)) {
            // 失效商品活动信息，不需要下架商品
            spuFeignClient.offlineSpuActivityByShopIds(shopIdsToStop);
            // 下架店铺商品
            spuFeignClient.offlineSpuByShopIds(shopIdsToStop);
        }
        // 修改购物车项中店铺是否停业属性
        ServerResponseEntity<Void> shopCartToStopRes = shopCartFeignClient.updateIsClosedByShopIds(shopIdsToStop, 0);
        if (shopCartToStopRes.isFail()) {
            throw new LuckException(shopCartToStopRes.getMsg());
        }
        ServerResponseEntity<Void> shopCartToOpenRes = shopCartFeignClient.updateIsClosedByShopIds(shopIdsToOpen, 1);
        if (shopCartToOpenRes.isFail()) {
            throw new LuckException(shopCartToOpenRes.getMsg());
        }
        // 下线优惠券满减活动
        offlineShopActivity(shopIdsToStop, ShopStatus.STOP.value());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#shopSigningInfoDTO.shopId")
    public void updateSigningInfo(ShopSigningInfoDTO shopSigningInfoDTO) {
        ShopDetailVO oldShopDetail = shopDetailMapper.getByShopId(shopSigningInfoDTO.getShopId());
        ShopDetail newShopDetail = mapperFacade.map(oldShopDetail, ShopDetail.class);
        // 赋值
        newShopDetail.setType(shopSigningInfoDTO.getType());
        newShopDetail.setContractStartTime(DateUtil.beginOfDay(shopSigningInfoDTO.getContractStartTime()));
        newShopDetail.setContractEndTime(getSaveEndOfDay(shopSigningInfoDTO.getContractEndTime()));
        // 当店铺状态处于营业中或者停业中时，店铺状态会受签约时间改变
        if (Objects.equals(newShopDetail.getShopStatus(), ShopStatus.OPEN.value()) || Objects.equals(newShopDetail.getShopStatus(), ShopStatus.STOP.value())) {
            Date now = new Date();
            // 记录店铺状态是否发生改变
            boolean isChangeStatus = false;
            if (now.compareTo(newShopDetail.getContractStartTime()) >= 0 && now.compareTo(newShopDetail.getContractEndTime()) < 0) {
                // 如果店铺的签约时间包含当前时间，则把店铺状态置为营业中
                isChangeStatus = Objects.equals(oldShopDetail.getShopStatus(), ShopStatus.STOP.value());
                newShopDetail.setShopStatus(ShopStatus.OPEN.value());
                shopDetailMapper.update(newShopDetail);
            } else if (now.compareTo(newShopDetail.getContractStartTime()) < 0 || now.compareTo(newShopDetail.getContractEndTime()) >= 0) {
                // 如果店铺的签约时间不包含当前时间，则把店铺状态置为停业中
                isChangeStatus = Objects.equals(oldShopDetail.getShopStatus(), ShopStatus.OPEN.value());
                newShopDetail.setShopStatus(ShopStatus.STOP.value());
                shopDetailMapper.update(newShopDetail);
            }
            ServerResponseEntity<Void> spuRes = spuFeignClient.updateSpuUpdateTimeByShopIds(Collections.singletonList(shopSigningInfoDTO.getShopId()), SysTypeEnum.MULTISHOP.value());
            if (spuRes.isFail()) {
                throw new LuckException(spuRes.getMsg());
            }
            // 如果店铺状态发生变化
            if (isChangeStatus) {
                // 更新购物车项店铺是否停业状态
                ServerResponseEntity<Void> shopCartRes = shopCartFeignClient.updateIsClosedByShopIds(Collections.singletonList(newShopDetail.getShopId()), Objects.equals(newShopDetail.getShopStatus(), ShopStatus.STOP.value()) ? 0 : 1);
                if (shopCartRes.isFail()) {
                    throw new LuckException(shopCartRes.getMsg());
                }
                if (Objects.equals(oldShopDetail.getShopStatus(), ShopStatus.OPEN.value())) {
                    // 店铺营业状态变为停业，需要下架商品活动
                    ServerResponseEntity<Void> offlineSpuActivityResp = spuFeignClient.offlineSpuActivityByShopIds(Collections.singletonList(newShopDetail.getShopId()));
                    if (offlineSpuActivityResp.isFail()) {
                        log.info("店铺营业状态变为停业，下架商品活动失败，店铺id：{}", newShopDetail.getShopId());
                        throw new LuckException(offlineSpuActivityResp.getMsg());
                    }
                    // 下架店铺商品
                    ServerResponseEntity<Void> offlineSpuResp = spuFeignClient.offlineSpuByShopIds(Collections.singletonList(newShopDetail.getShopId()));
                    if (offlineSpuResp.isFail()) {
                        log.info("店铺营业状态变为停业，下架店铺商品失败，店铺id：{}", newShopDetail.getShopId());
                        throw new LuckException(offlineSpuResp.getMsg());
                    }
                    // 下线满减和优惠券活动
                    offlineShopActivity(Collections.singletonList(newShopDetail.getShopId()), ShopStatus.STOP.value());
                }
            }
        }
        // 店铺违规下线、违规提交审核时，修改签约时间和店铺类型，不修改状态
        else {
            shopDetailMapper.update(newShopDetail);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#offlineHandleEventDTO.handleId")
    public void auditApply(OfflineHandleEventDTO offlineHandleEventDTO) {
        ShopDetailVO shopDetailVO = getByShopId(offlineHandleEventDTO.getHandleId());
        if (Objects.isNull(shopDetailVO)) {
            throw new LuckException("店铺不存在");
        }
        if (!Objects.equals(shopDetailVO.getShopStatus(), ShopStatus.OFFLINE.value())) {
            throw new LuckException("店铺状态已发生变化，请刷新后重试");
        }
        // 更新事件状态
        ServerResponseEntity<Void> offlineRes = offlineHandleEventFeignClient.updateToApply(offlineHandleEventDTO);
        if (offlineRes.isFail()) {
            throw new LuckException(offlineRes.getMsg());
        }
        // 更改店铺状态为上线申请待审核
        shopDetailMapper.changeShopStatus(offlineHandleEventDTO.getHandleId(), ShopStatus.OFFLINE_AWAIT_AUDIT.value());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @GlobalTransactional(rollbackFor = Exception.class)
    @CacheEvict(cacheNames = CacheNames.SHOP_DETAIL_ID_KEY, key = "#offlineHandleEventDTO.handleId")
    public void onlineAudit(OfflineHandleEventDTO offlineHandleEventDTO) {
        ShopDetailVO shopDetail = getByShopId(offlineHandleEventDTO.getHandleId());
        if (Objects.isNull(shopDetail)) {
            throw new LuckException("店铺不存在");
        }
        if (!Objects.equals(shopDetail.getShopStatus(), ShopStatus.OFFLINE_AWAIT_AUDIT.value())) {
            throw new LuckException("店铺状态已发生变化，请刷新后重试");
        }
        // 审核
        ServerResponseEntity<Void> responseEntity = offlineHandleEventFeignClient.auditOfflineEvent(offlineHandleEventDTO);
        if (!Objects.equals(responseEntity.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(responseEntity.getMsg());
        }
        Date now = new Date();
        Long shopId = offlineHandleEventDTO.getHandleId();
        // 审核通过
        if (Objects.equals(offlineHandleEventDTO.getStatus(), OfflineHandleEventStatus.AGREE_BY_PLATFORM.getValue())) {
            if (now.compareTo(shopDetail.getContractStartTime()) >= 0 && now.compareTo(shopDetail.getContractEndTime()) < 0) {
                // 如果店铺的签约时间包含当前时间，则把店铺状态置为营业中
                shopDetailMapper.changeShopStatus(shopId, ShopStatus.OPEN.value());
                // 更新购物车项店铺是否停业状态
                shopCartFeignClient.updateIsClosedByShopIds(Collections.singletonList(shopDetail.getShopId()), 1);
            } else {
                // 如果店铺的签约时间不包含当前时间，则把店铺状态置为停业中
                shopDetailMapper.changeShopStatus(shopId, ShopStatus.STOP.value());
                // 更新购物车项店铺是否停业状态
                shopCartFeignClient.updateIsClosedByShopIds(Collections.singletonList(shopDetail.getShopId()), 0);
            }
            spuFeignClient.updateSpuUpdateTimeByShopIds(Collections.singletonList(shopId), SysTypeEnum.MULTISHOP.value());
        }
        // 审核不通过
        else if (Objects.equals(offlineHandleEventDTO.getStatus(), OfflineHandleEventStatus.DISAGREE_BY_PLATFORM.getValue())) {
            shopDetailMapper.changeShopStatus(shopId, ShopStatus.OFFLINE.value());
        }
    }

    @Override
    public List<ShopSimpleBO> listSimple(ShopSimpleBO shopSimpleBO) {
        return shopDetailMapper.listSimple(shopSimpleBO);
    }

    @Override
    public Boolean checkShopName(String shopName) {
        return shopDetailMapper.countShopName(shopName, null) > 0;
    }

    @Override
    public List<Long> getShopIdByShopStatus(Integer shopStatus) {
        return shopDetailMapper.getShopIdsByShopStatus(shopStatus);
    }

    @Override
    public void offlineShopActivity(List<Long> shopIds, Integer shopStatus) {
        if (!Objects.equals(shopStatus, ShopStatus.STOP.value()) && Objects.equals(shopStatus, ShopStatus.OFFLINE.value())) {
            return;
        }
        //下线满减活动
        ServerResponseEntity<Void> handleDiscountOffline = discountFeignClient.handleShopOffline(shopIds);
        if (handleDiscountOffline.isFail()) {
            throw new LuckException(handleDiscountOffline.getMsg());
        }
        //下线优惠券
        ServerResponseEntity<Void> handleCouponOffline = couponFeignClient.handleShopOffline(shopIds);
        if (handleCouponOffline.isFail()) {
            throw new LuckException(handleCouponOffline.getMsg());
        }
    }

    @Override
    public List<Long> getShopIdsLikeName(String name) {
        return shopDetailMapper.selectShopIdsLikeName(name);
    }

    @Override
    public PageVO<ShopHeadInfoVO> renovationShopPage(PageDTO pageDTO, ShopSearchDTO shopSearchDTO, Integer sysType) {
        if (Objects.equals(sysType, SysTypeEnum.ORDINARY.value())) {
            PageUtil.doPage(pageDTO, () -> shopDetailMapper.apiSearchShops(shopSearchDTO));
        }
        return PageUtil.doPage(pageDTO, () -> shopDetailMapper.searchShops(shopSearchDTO));
    }

    @Override
    public List<ShopHeadInfoVO> listRenovationShop(ShopSearchDTO shopSearchDTO) {
        if (CollUtil.isEmpty(shopSearchDTO.getShopIds())) {
            return new ArrayList<>();
        }
        return shopDetailMapper.listRenovationShop(shopSearchDTO);
    }

    @Override
    public List<Map<String,Object>> group_area_count(Long cateId) {
        return shopDetailMapper.group_area_count(cateId);
    }

    @Override
    public List<String> getShopNameByArea(Long areaId, Integer level) {
        return shopDetailMapper.getShopNameByArea(areaId,level);

    }

    /**
     * 添加店铺钱包
     * @param shopId
     * @return
     */
    public void addShopInfo(Long shopId) {
        ShopExtension shopExtension = new ShopExtension();
        shopExtension.setShopId(shopId);
        shopExtensionService.save(shopExtension);

        ShopWallet shopWallet = new ShopWallet();
        shopWallet.setVersion(0L);
        shopWallet.setUnsettledAmount(0L);
        shopWallet.setSettledAmount(0L);
        shopWallet.setFreezeAmount(0L);
        shopWallet.setTotalSettledAmount(0L);
        shopWallet.setSmsNum(0);
        shopWallet.setZoneNum(ShopWalletZoneConstant.ZERO);
        shopWallet.setShopId(shopId);
        shopWalletMapper.save(shopWallet);
    }

    /**
     * 检验店铺信息是否正确
     * @param shopDetailDTO 店铺基本信息
     * @param isCreate true: 创建时校验， false: 更新时校验
     */
    private void checkShopInfo(ShopDetailDTO shopDetailDTO, Boolean isCreate) {
        if (!isCreate) {
            ShopAuditingVO shopAuditingVO = shopAuditingService.getByshopId(shopDetailDTO.getShopId());
            if (Objects.nonNull(shopAuditingVO) && Objects.equals(shopAuditingVO.getStatus(), AuditStatus.WAITAUDIT.value())) {
                throw new LuckException("店铺处于待审核状态无法修改信息");
            }
        }
        // 店铺名称
        if (StrUtil.isNotBlank(shopDetailDTO.getShopName())) {
            shopDetailDTO.setShopName(shopDetailDTO.getShopName().trim());
        }
        if(shopDetailMapper.countShopName(shopDetailDTO.getShopName(), shopDetailDTO.getShopId()) > 0) {
            throw new LuckException("店铺名称已存在");
        }
        if (!isCreate) {
            // 更新店铺基本信息不用校验用户信息
            return;
        }
        // 手机号、邮箱
        if (StrUtil.isNotBlank(shopDetailDTO.getEmail())) {
            shopDetailDTO.setEmail(shopDetailDTO.getEmail().trim());
        }
        if (StrUtil.isNotBlank(shopDetailDTO.getContactPhone())) {
            shopDetailDTO.setPhone(shopDetailDTO.getContactPhone().trim());
        }
    }

    /**
     * 创建店铺初始账号
     * @param shopDetailDTO
     * @param statusEnum
     */
    public void createShopAccount(ShopDetailDTO shopDetailDTO, StatusEnum statusEnum) {
        ShopUser shopUser = new ShopUser();
        shopUser.setShopId(shopDetailDTO.getShopId());
        shopUser.setHasAccount(1);
        shopUser.setNickName(shopDetailDTO.getUsername());
        shopUserService.save(shopUser, null);

        AuthAccountDTO authAccountDTO = new AuthAccountDTO();
        authAccountDTO.setEmail(shopDetailDTO.getEmail());
        authAccountDTO.setPhone(shopDetailDTO.getPhone());
        authAccountDTO.setUsername(shopDetailDTO.getUsername());
        authAccountDTO.setPassword(shopDetailDTO.getPassword().trim());
        authAccountDTO.setStatus(statusEnum.value());
        authAccountDTO.setSysType(SysTypeEnum.MULTISHOP.value());
        authAccountDTO.setCreateIp(IpHelper.getIpAddr());
        authAccountDTO.setTenantId(shopDetailDTO.getShopId());
        authAccountDTO.setUserId(shopUser.getShopUserId());
        authAccountDTO.setIsAdmin(UserAdminType.ADMIN.value());
        ServerResponseEntity<Long> save = accountFeignClient.save(authAccountDTO);
        if (!Objects.equals(save.getCode(), ResponseEnum.OK.value())) {
            throw new LuckException(save.getMsg());
        }
    }

    private Date getSaveEndOfDay(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(DateUtil.endOfDay(date));
        // 防止时间进位
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTime();
    }
}
